/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-08-13 08:26:24
 * @LastEditTime: 2021-08-23 17:12:55
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */

#include "fgdma_hw.h"
#include "fgdma.h"
#include "fsleep.h"
#include "ft_assert.h"
#include "parameters.h"

void FGdmaDisabled(FGdma *instance_p)
{
    u32 reg_value;

    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_CTL_OFFSET);
    reg_value &= ~FGDMA_GLOBAL_CTL_ENABLE_MASK;
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_CTL_OFFSET, reg_value);
}

void FGdmaEnable(FGdma *instance_p)
{
    u32 reg_value;
    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_CTL_OFFSET);
    reg_value |= FGDMA_GLOBAL_CTL_ENABLE_MASK;
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_CTL_OFFSET, reg_value);
}

void FGdmaReset(FGdma *instance_p)
{
    u32 reg_value;
    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_CTL_OFFSET);
    reg_value |= FGDMA_GLOBAL_CTL_SOFT_RESET_MASK;
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_CTL_OFFSET, reg_value);

    fsleep_microsec(10);
    reg_value &= ~FGDMA_GLOBAL_CTL_SOFT_RESET_MASK;
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_CTL_OFFSET, reg_value);
}

void FGdmaIrqEnable(FGdma *instance_p)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET);
    reg_value |= FGDMA_GLOBAL_CTRL_GLOBAL_INTR_ENABLE_MASK;
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET, reg_value);
}

void FGdmaIrqDisable(FGdma *instance_p)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET);
    reg_value &= ~FGDMA_GLOBAL_CTRL_GLOBAL_INTR_ENABLE_MASK;
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET, reg_value);
}

/* Channel */
void FGdmaChClkOn(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);

    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_CHANNEL_LOW_POWER_CONTROL_OFFSET);
    reg_value &= ~GENMASK(index, index);
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_CHANNEL_LOW_POWER_CONTROL_OFFSET, reg_value);
}

void FGdmaChClkOff(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);

    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_CHANNEL_LOW_POWER_CONTROL_OFFSET);
    reg_value |= GENMASK(index, index);
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_CHANNEL_LOW_POWER_CONTROL_OFFSET, reg_value);
}

void FGdmaChIrqDisable(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);
    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET);
    reg_value &= ~GENMASK(index, index);
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET, reg_value);
}

void FGdmaChIrqEnable(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);

    FGDMA_WRITEREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_INT_CTRL_OFFSET, FGDMA_CHX_INT_CTRL_TRANS_END_ENABLE_MASK);

    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET);
    reg_value |= GENMASK(index, index);
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET, reg_value);
}

void FGdmaChBdlIrqEnable(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);

    FGDMA_WRITEREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_INT_CTRL_OFFSET, FGDMA_CHX_INT_CTRL_BDL_END_ENABLE_MASK);

    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET);
    reg_value |= GENMASK(index, index);
    FGDMA_WRITEREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_CTRL_OFFSET, reg_value);
}

void FGdmaChIrqClear(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);
    FGDMA_WRITEREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_INT_STATE_OFFSET, FGDMA_CHX_INT_CTRL_TRANS_END_ENABLE_MASK);
}

u32 FGdmaChIrqRead(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTNONVOID(instance_p != NULL);
    FT_ASSERTNONVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTNONVOID(index < FGDMA_CHANNEL_MAX_NUM);
    reg_value = FGDMA_READREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_INT_STATE_OFFSET);
    reg_value &= (0x1 << index);
    return reg_value;
}

u32 FGdmaChStatusRead(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTNONVOID(instance_p != NULL);
    FT_ASSERTNONVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTNONVOID(index < FGDMA_CHANNEL_MAX_NUM);
    reg_value = FGDMA_READREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_INT_STATE_OFFSET);
    reg_value &= 0x1f;
    return reg_value;
}

void FGdmaChDisable(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);
    reg_value = FGDMA_READREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_CTL_OFFSET);
    reg_value &= ~FGDMA_CHX_CTL_ENABLE_MASK;
    FGDMA_WRITEREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_CTL_OFFSET, reg_value);
}

void FGdmaChReset(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);
    reg_value = FGDMA_READREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_CTL_OFFSET);
    reg_value &= ~FGDMA_CHX_CTL_SOFT_RESET_MASK;
    FGDMA_WRITEREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_CTL_OFFSET, reg_value);

    fsleep_microsec(10);
    reg_value &= ~FGDMA_CHX_CTL_SOFT_RESET_MASK;
    FGDMA_WRITEREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_CTL_OFFSET, reg_value);
}

void FGdmaChEnable(FGdma *instance_p, FGdmaChIndex index)
{
    u32 reg_value;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID(index < FGDMA_CHANNEL_MAX_NUM);
    reg_value = FGDMA_READREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_CTL_OFFSET);
    reg_value |= FGDMA_CHX_CTL_ENABLE_MASK;
    FGDMA_WRITEREG(instance_p->config.dma_channel_config[index].dma_channel_addr, FGDMA_CHX_CTL_OFFSET, reg_value);
}

void FGdmaHwInit(FGdma *instance_p)
{
    u32 reg_value;
    u32 i;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);

    FGdmaDisabled(instance_p);
    FGdmaReset(instance_p);

    FGdmaIrqEnable(instance_p);
    FGdmaEnable(instance_p);
    for (i = 0; i < FGDMA_CHANNEL_MAX_NUM; i++)
    {
        FGdmaChDisable(instance_p, i);
        FGdmaChIrqDisable(instance_p, i);
        FGdmaChReset(instance_p, i);
    }
}